//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "NXP_MP4Enc.h"

#define MP4Enc_SetParam     0x00
#define MP4Enc_Enc          0x01
#define MP4Enc_Uninit       0x02

typedef void *(*PFunmalloc)(size_t);
typedef void (*PFunfree)(void *);

void **g_Mp4EncApiForZener;

#define DEFINE_MP4DEC_API(func_ptr_type, index) \
            ((func_ptr_type)g_Mp4EncApiForZener[index])

#define nu_Mp4EncInit     DEFINE_MP4DEC_API(void(*)(unsigned long , unsigned long ,unsigned long ,unsigned long, M4V_COLOUR_FORMAT , M4ViComU8, PFunmalloc, PFunfree),   0)
#define nu_Mp4Encode      DEFINE_MP4DEC_API(int (*)(char *, char *, unsigned long ,unsigned long , unsigned long *),     1)
#define nu_Mp4EncUninit   DEFINE_MP4DEC_API(void(*)(void),  2)            

IDeviceDriver * CDECL CreateMP4Encoder(
    /* [in] */ uint_t deviceNo,
    /* [in] */ void* parameter)
{
    CMPEG4Enc* MPEG4Encoder = new CMPEG4Enc;
    if (!MPEG4Encoder) {
        DRV_EXPRESSION(ERRORLEVEL, kprintf("Not enough memory\n"));

        return NULL;
    }

    MPEG4Encoder->AddRef();

    ECode ec = MPEG4Encoder->constructor();
    if (DRV_FAILED(ec)) {
        MPEG4Encoder->Release();
        return NULL;
    }
    
    g_Mp4EncApiForZener = nu_FM4ViEnc_GetAPIs();
    return (IDeviceDriver *)MPEG4Encoder;
}

ECode CMPEG4Enc::constructor()
{ 
    return NOERROR;
}

ECode CMPEG4Enc::Control(
    /* [in] */ Handle32 controlCode,
    /* [in] */ const MemoryBuf &inBuffer,
    /* [out] */ MemoryBuf* pOutBuffer,
    /* [out] */ IEvent** ppCompletionEvent)
{
    ECode ec = NOERROR;
    UInt32 uGotSize = 0;
    
    switch (controlCode) {
        case MP4Enc_SetParam: {
            if (inBuffer.IsNullOrEmpty()) {
                return E_INVALID_ARGUMENT;
            }
            
            int *pinData = (int *)inBuffer.GetPayload();

            UInt32  FrameWidth = (UInt32)(*pinData);
            UInt32  FrameHeight = (UInt32)(*(pinData + 1));
            UInt32  CaptureRateNumerator = (UInt32)(*(pinData + 2));
            UInt32  CaptureRateDenominator = (UInt32)(*(pinData + 3));
            M4V_COLOUR_FORMAT frameType = (M4V_COLOUR_FORMAT)(*(pinData + 4));
            M4ViComU8 nMotionQualityFactor = (M4ViComU8)(*(pinData + 5));
            
            nu_Mp4EncInit(FrameWidth, FrameHeight, CaptureRateNumerator, CaptureRateDenominator, frameType, 
                    nMotionQualityFactor, malloc, free);
                    
            break;
        }
        
        
        // M4ViEncoder
        //
        case MP4Enc_Enc: { 
            if (inBuffer.IsNullOrEmpty() || pOutBuffer->IsNull()) {
                return E_INVALID_ARGUMENT;
            }
  
            ec = nu_Mp4Encode((char *)inBuffer.GetPayload(),
                        (char *)pOutBuffer->GetPayload(),
                        inBuffer.GetUsed(),
                        pOutBuffer->GetCapacity(),
                        (unsigned long  *)&uGotSize);
            pOutBuffer->SetUsed(uGotSize);
            
            break;
        }
        
        //M4ViFree
        case MP4Enc_Uninit: {
            nu_Mp4EncUninit();
            break;
        }
        
        default:
            ec = E_NOT_IMPLEMENTED;
            break;
    }

    return ec;
}
